package com.gopay.scheduler.service.cbrmb.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.gopay.common.constants.cbrmb.CbRmbBankConstants;
import com.gopay.common.constants.cbrmb.CbRmbBankOrderState;
import com.gopay.common.constants.cbrmb.CbRmbOrderState;
import com.gopay.common.constants.cbrmb.CbRmbPayDirection;
import com.gopay.common.cps.dao.cbrmb.CbBankAcctDao;
import com.gopay.common.cps.dao.cbrmb.CbRmbBankMessageDtlDao;
import com.gopay.common.cps.dao.cbrmb.CbRmbBankOrderDtlDao;
import com.gopay.common.cps.dao.cbrmb.CbRmbBankOrderMessageRelDao;
import com.gopay.common.cps.dao.cbrmb.CbRmbBankRestoreDtlDao;
import com.gopay.common.cps.dao.cbrmb.CbRmbTranAssistDtlDao;
import com.gopay.common.cps.dao.cbrmb.CbRmbTranAssistDtlLogDao;
import com.gopay.common.cps.dao.order.CpsGeneralMainOrderQueryDAO;
import com.gopay.common.domain.bank.ccb.cbrmb.CbRmbXmlFile;
import com.gopay.common.domain.bank.ccb.cbrmb.CbRmbXmlFileBody;
import com.gopay.common.domain.bank.ccb.cbrmb.CbRmbXmlFileHead;
import com.gopay.common.domain.bank.ccb.cbrmb.CbRmbXmlFileRestoreDetail;
import com.gopay.common.domain.bank.ccb.cbrmb.req.CbRmbNotificationMsg;
import com.gopay.common.domain.bank.ccb.cbrmb.res.CbRmbResponseMsg;
import com.gopay.common.domain.cbrmb.CbBankAcct;
import com.gopay.common.domain.cbrmb.CbRmbBankMessageDtl;
import com.gopay.common.domain.cbrmb.CbRmbBankOrderDtl;
import com.gopay.common.domain.cbrmb.CbRmbBankOrderMessageRel;
import com.gopay.common.domain.cbrmb.CbRmbBankRestoreDtl;
import com.gopay.common.domain.cbrmb.CbRmbTranAssistDtl;
import com.gopay.common.domain.cbrmb.CbRmbTranAssistDtlLog;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.cbrmb.BeanMapper;
import com.gopay.common.util.cbrmb.FileUtils;
import com.gopay.common.util.cbrmb.FtpUtils;
import com.gopay.common.util.cbrmb.MsgUtils;
import com.gopay.remote.bank.cbrmb.CbRmbCcbBankRemoteService;
import com.gopay.scheduler.service.cbrmb.CbRmbPayForCcbService;

/**
 * 
 * @ClassName: CbRmbSettlementServiceImpl
 * @Description: 跨境人民币结算
 * @author gd.cui
 * @date 2016年7月12日 下午4:55:36 ww.gopay.com.cn Inc.All rights reserved.
 */
@Service("cbRmbPayForCcbService")
public class CbRmbPayForCcbServiceImpl implements CbRmbPayForCcbService {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Resource(name = "cbRmbCcbBankRemoteServiceClient")
	private CbRmbCcbBankRemoteService cbRmbCcbBankRemoteServiceClient;

	@Resource(name = "cbRmbBankOrderDtlDao")
	private CbRmbBankOrderDtlDao cbRmbBankOrderDtlDao;

	@Resource(name = "cbRmbBankOrderMessageRelDao")
	private CbRmbBankOrderMessageRelDao cbRmbBankOrderMessageRelDao;

	@Resource(name = "cbRmbBankMessageDtlDao")
	private CbRmbBankMessageDtlDao cbRmbBankMessageDtlDao;

	@Resource(name = "cbRmbTranAssistDtlDao")
	private CbRmbTranAssistDtlDao cbRmbTranAssistDtlDao;

	@Resource(name = "cbRmbBankRestoreDtlDao")
	private CbRmbBankRestoreDtlDao cbRmbBankRestoreDtlDao;

	@Resource(name = "cpsGeneralMainOrderQueryDAO")
	private CpsGeneralMainOrderQueryDAO cpsGeneralMainOrderQueryDAO;

	@Resource(name = "cbBankAcctDao")
	private CbBankAcctDao cbBankAcctDao;

	@Resource(name = "cbrConfig")
	private Map<String, String> cbrConfig;

	@Resource(name = "cbRmbTranAssistDtlLogDao")
	private CbRmbTranAssistDtlLogDao cbRmbTranAssistDtlLogDao;

	/**
	 * 建行付款到境外，结算
	 */
	@Override
	public void payForCcb(CbRmbTranAssistDtl cbRmbTranAssistDtl) {

		List<CbRmbTranAssistDtl> cbRmbTranAssistDtls = Lists.newArrayList(cbRmbTranAssistDtl);
		/************** 初始化待结算数据 ***********************/
		CbRmbBankOrderMessageRel rel = new CbRmbBankOrderMessageRel();
		List<CbRmbBankOrderDtl> orderDtls = Lists.newArrayList();
		List<CbRmbXmlFileBody> cbRmbXmlFileBodys = Lists.newArrayList();
		initOfferData(cbRmbTranAssistDtls, rel, orderDtls, cbRmbXmlFileBodys);
		/************** 组装文件数据 ***********************/
		CbRmbXmlFileHead cbRmbXmlFileHead = BeanMapper.map(rel, CbRmbXmlFileHead.class);
		CbRmbXmlFile xmlFile = new CbRmbXmlFile();
		xmlFile.setCbRmbXmlFileHead(cbRmbXmlFileHead);
		xmlFile.setCbRmbXmlFileBody(cbRmbXmlFileBodys);
		boolean isSuccessed = false;
		String reqXml = CbRmbBankConstants.XML_HEAD + BeanMapper.toXml(xmlFile);
		try {
			isSuccessed = writerAndUploadFile(reqXml);
		} catch (Exception e) {
			logger.error(" 文件生成或文件上传失败");
			e.printStackTrace();
		}
		if (isSuccessed) {
			/************** 先保存后通知:此处应该先通知后保存数据 ***********************/
			cbRmbTranAssistDtl.setState(CbRmbOrderState.OFFER_ONGOING.value);
			cbRmbTranAssistDtlDao.update(cbRmbTranAssistDtl);
			rel.setReqXml(reqXml);
			rel.setCreateTime(new Date());
			rel.setLastUpdateTime(new Date());
			cbRmbBankOrderMessageRelDao.save(rel);
			logger.error("*****报盘-xml头信息 orderMessageId=" + rel.getOrderMessageId());
			for (CbRmbBankOrderDtl order : orderDtls) {
				order.setOrderMessageId(rel.getOrderMessageId());
				order.setState(CbRmbBankOrderState._00.value);// 进行中
				order.setLastUpdateTime(new Date());
				logger.error("*****报盘-待报盘数据：gopayorderid=" + order.getGopayOrderId());
			}
			cbRmbBankOrderDtlDao.saveOrUpdateAll(orderDtls);
			CbRmbBankMessageDtl message = new CbRmbBankMessageDtl(file);
			message.setOrderMessageId(rel.getOrderMessageId());
			message.setCreateTime(new Date());
			message.setLastUpdateTime(new Date());
			cbRmbBankMessageDtlDao.save(message);
			logger.error("*****报盘-通知报文信息 待报盘数据：messageId=" + message.getMessageId() + ",orderMessageId="
					+ message.getOrderMessageId());
			CbRmbNotificationMsg msg = BeanMapper.map(message, CbRmbNotificationMsg.class);
			CbRmbResponseMsg returnMsg = null;
			try {
				returnMsg = cbRmbCcbBankRemoteServiceClient.submit(msg);
			} catch (GopayException e) {
				e.printStackTrace();
				logger.error("*****报盘-银行通信异常");
			}
			if (returnMsg != null) {
				message.setRetCode(returnMsg.getRetCode());
				message.setRetMsg(returnMsg.getRetMsg());
				cbRmbBankMessageDtlDao.update(message);
			}
			if (returnMsg != null && CbRmbBankConstants.SUCCESS.equals(returnMsg.getRetCode())) {
				for (CbRmbBankOrderDtl order : orderDtls) {
					order.setOrderMessageId(rel.getOrderMessageId());
					order.setState(CbRmbBankOrderState._01.value);
					order.setLastUpdateTime(new Date());
					logger.error("*****报盘-报盘完成： gopayorderid=" + order.getGopayOrderId());
				}
				cbRmbBankOrderDtlDao.saveOrUpdateAll(orderDtls);
				cbRmbTranAssistDtl.setBpFinishTime(new Date());
				cbRmbTranAssistDtl.setState(CbRmbOrderState.OFFER_SUCCESS.value);
				cbRmbTranAssistDtlDao.update(cbRmbTranAssistDtl);
			} else {
				logger.error("*****报盘失败 code:" + message.getRetCode() + ",msg:" + message.getRetMsg());
				for (CbRmbBankOrderDtl order : orderDtls) {
					order.setOrderMessageId(rel.getOrderMessageId());
					order.setState(CbRmbBankOrderState._02.value);
					order.setLastUpdateTime(new Date());
					logger.error("*****报盘-报盘完成： gopayorderid=" + order.getGopayOrderId());
					CbRmbTranAssistDtlLog assistLog = new CbRmbTranAssistDtlLog();
					assistLog.setMessageId(message.getMessageId());
					assistLog.setCreateTime(new Date());
					assistLog.setLastUpdateTime(new Date());
					assistLog.setGopayOrderId(order.getGopayOrderId());
					assistLog.setReturnCode(message.getRetCode());
					assistLog.setReturnInfo(message.getRetMsg());
					assistLog.setTranType("0");// 0报盘,1回盘,2付款
					cbRmbTranAssistDtlLogDao.save(assistLog);
				}
				cbRmbBankOrderDtlDao.saveOrUpdateAll(orderDtls);
				cbRmbTranAssistDtl.setBpFinishTime(new Date());
				cbRmbTranAssistDtl.setState(CbRmbOrderState.PAY_FAIL.value);
				cbRmbTranAssistDtlDao.update(cbRmbTranAssistDtl);
			}
		}
	}

	private void initOfferData(List<CbRmbTranAssistDtl> cbRmbTranAssistDtls, CbRmbBankOrderMessageRel rel,
			List<CbRmbBankOrderDtl> orderDtls, List<CbRmbXmlFileBody> cbRmbXmlFileBodys) {
		rel.setTradedate(MsgUtils.date2StrYYYYMMDD(new Date()));
		rel.setTotalcount(cbRmbTranAssistDtls.size());
		rel.setTotalamt(new BigDecimal("0.00"));
		for (int i = 0; i < cbRmbTranAssistDtls.size(); i++) {
			CbRmbTranAssistDtl tranAssist = cbRmbTranAssistDtls.get(i);
			// 1、获取主订单 根据gopayorderid
			CpsGenMainOrder mainOrder = cpsGeneralMainOrderQueryDAO.findByGopayOrderId(tranAssist.getGopayOrderId());
			if (mainOrder == null) {
				logger.error("主订单为为空，gopayOrderId=" + tranAssist.getGopayOrderId());
			}
			// 2、获取银行卡信息
			CbBankAcct bankAcct = cbBankAcctDao.find(CbBankAcct.class, tranAssist.getReceiverId());
			if (bankAcct == null) {
				logger.error("主订单为为空，receiverId=" + tranAssist.getReceiverId());
			}
			CbRmbBankOrderDtl orderDtl = new CbRmbBankOrderDtl();
			orderDtl.setCreateTime(new Date());
			orderDtl.setGopayOrderId(tranAssist.getGopayOrderId());
			orderDtl.setTransDate(MsgUtils.date2StrYYYYMMDD(new Date()));
			orderDtl.setPayeeName(bankAcct.getReceiverName().replace("&#39;", "'").replace("&#43;", "+"));// 转义单引号和加好
																											// 20161206
			orderDtl.setPayeeCountryNo(bankAcct.getReceiverCountry());
			orderDtl.setPayeeBankName(bankAcct.getReceiverBankName());
			orderDtl.setPayeeAccountNo(bankAcct.getReceiverAccount());
			orderDtl.setPayeeBankNo(bankAcct.getPbocCode());
			orderDtl.setPayeeBankSwift(bankAcct.getReceiverSwiftCode());
			orderDtl.setPaydirection(CbRmbPayDirection.ABROAD.value);// 交易方向，境内到境外(01)/境外到境内(02)
			orderDtl.setOrderamt(new BigDecimal("0.00").add(mainOrder.getMerTxnAmt()));
			orderDtl.setOrdercur(CbRmbBankConstants.CNY);// 默认CNY
			orderDtl.setTradeType(StringUtils.startsWith(tranAssist.getTradeCode(), "1") ? "02" : "01");// 贸易类型，服务贸易01/货物贸易02
			orderDtl.setIsbonded(tranAssist.getIsbonded());
			orderDtl.setTradeCode(tranAssist.getTradeCode());
			orderDtl.setTradeComment(tranAssist.getTradeDesc());
			orderDtl.setTradeDesc(tranAssist.getTradeDesc());
			orderDtl.setRestoreNeeded(tranAssist.getRestoreNeeded());
			orderDtl.setLastUpdateTime(new Date());
			rel.setTotalamt(rel.getTotalamt().add(orderDtl.getOrderamt()));
			CbRmbXmlFileBody cbRmbXmlFileBody = BeanMapper.map(orderDtl, CbRmbXmlFileBody.class);
			if (orderDtl.getRestoreNeeded().equals(CbRmbBankConstants.YES)) {
				List<CbRmbBankRestoreDtl> restoreDtls = cbRmbBankRestoreDtlDao
						.findByGopayOrderId(cbRmbTranAssistDtls.get(i).getGopayOrderId());
				for (CbRmbBankRestoreDtl restoreDtl : restoreDtls) {
					restoreDtl.setPayerAmt(new BigDecimal("0.00").add(restoreDtl.getPayerAmt()));
				}
				List<CbRmbXmlFileRestoreDetail> restoreDetail = BeanMapper.mapList(restoreDtls,
						CbRmbXmlFileRestoreDetail.class);
				cbRmbXmlFileBody.setCbRmbXmlFileRestoreDetail(restoreDetail);
			}
			cbRmbXmlFileBodys.add(cbRmbXmlFileBody);
			orderDtls.add(orderDtl);
		}
	}

	private boolean writerAndUploadFile(String content) throws Exception {
		File file = createFile();
		FileUtils.writerXmlFile(content, file, CbRmbBankConstants.CHARSET_GBK);
		InputStream inputStream = new FileInputStream(file);
		FtpUtils ftp = new FtpUtils(cbrConfig.get("ftp.ip"), Integer.valueOf(cbrConfig.get("ftp.port")),
				cbrConfig.get("ftp.username"), cbrConfig.get("ftp.password"), cbrConfig.get("ftp.upload.path"));
		return ftp.uploadFile(file.getName(), inputStream, CbRmbBankConstants.CHARSET_GBK);
	}

	private File file;

	private File createFile() {
		String fileName = "KJZFLP_" + MsgUtils.date2StrYYYYMMDD(new Date()) + "_" + MsgUtils.getFileSeq() + ".xml";
		file = new File(cbrConfig.get("local.upload.path") + fileName);
		if (file.exists()) {
			createFile();
		}
		return file;
	}

	public static void main(String args[]) throws Exception, IOException {

	}

}
